﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.NetworkAnalyst;
using Entity;

namespace Utilities
{
    public class RouteClass
    {
        private const String FGDB_WORKSPACE = @"E:\VirtualCampus\ArcGlobeData\ZhiMingBuilding\Campus3D\BuildingWay.gdb";
        //private const String FGDB_WORKSPACE = @"\..\..\..\..\..\Data\SanFrancisco\SanFrancisco.gdb";
        private const String INPUT_STOPS_FC = "stops";
        private const String INPUT_NAME_FIELD = "Name";
        private const String FEATURE_DATASET = "Transportation";
        private const String NETWORK_DATASET = "Transportation_ND";

        ////private const String FGDB_WORKSPACE = @"E:\VirtualCampus\RouteAnalysis\3DRoutAnalysis\data\3DRouteAnalysis.gdb";
        ////private const String INPUT_STOPS_FC = "InputStops";
        ////private const String INPUT_NAME_FIELD = "Name";
        ////private const String FEATURE_DATASET = "Transportation";
        ////private const String NETWORK_DATASET = "WalkWay_ND";

        /// <summary>
        /// Create the analysis layer, load the locations, solve the analysis, and write to disk
        /// </summary>

        public void SolveRoute(out Collection<ERouteNode> nodes)
        {            
            // Open the feature workspace, input feature class, and network dataset
            // As Workspace Factories are Singleton objects, they must be instantiated with the Activator
            IWorkspaceFactory workspaceFactory = System.Activator.CreateInstance(System.Type.GetTypeFromProgID("esriDataSourcesGDB.FileGDBWorkspaceFactory")) as IWorkspaceFactory;
            IFeatureWorkspace featureWorkspace = workspaceFactory.OpenFromFile(FGDB_WORKSPACE, 0) as IFeatureWorkspace;            
            IFeatureClass inputStopsFClass = featureWorkspace.OpenFeatureClass(INPUT_STOPS_FC);

            // Obtain the dataset container from the workspace
            ESRI.ArcGIS.Geodatabase.IFeatureDataset featureDataset = featureWorkspace.OpenFeatureDataset(FEATURE_DATASET);
            var featureDatasetExtensionContainer = featureDataset as ESRI.ArcGIS.Geodatabase.IFeatureDatasetExtensionContainer;
            ESRI.ArcGIS.Geodatabase.IFeatureDatasetExtension featureDatasetExtension = featureDatasetExtensionContainer.FindExtension(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTNetworkDataset);
            var datasetContainer3 = featureDatasetExtension as ESRI.ArcGIS.Geodatabase.IDatasetContainer3;

            // Use the container to open the network dataset.
            ESRI.ArcGIS.Geodatabase.IDataset dataset = datasetContainer3.get_DatasetByName(ESRI.ArcGIS.Geodatabase.esriDatasetType.esriDTNetworkDataset, NETWORK_DATASET);
            INetworkDataset networkDataset = dataset as INetworkDataset;

            // Create the Route NALayer
            INALayer naLayer = CreateRouteAnalysisLayer("Route", networkDataset);
            INAContext naContext = naLayer.Context;
            //INAClass即为每个分析的结点，包括Stops、Routes、Facility等等
            INAClass stopsNAClass = naContext.NAClasses.get_ItemByName("Stops") as INAClass;
            IFeatureClass routesFC = naContext.NAClasses.get_ItemByName("Routes") as IFeatureClass;

            // Load the Stops
            INAClassFieldMap naClassFieldMap = new NAClassFieldMapClass();
            naClassFieldMap.set_MappedField("Name", INPUT_NAME_FIELD);

            INAClassLoader naLoader = new NAClassLoaderClass();
            naLoader.Locator = naContext.Locator;
            naLoader.NAClass = stopsNAClass;
            naLoader.FieldMap = naClassFieldMap;

            // Avoid loading network locations onto non-traversable portions of elements
            //如果到了有限制和方向的，这里需要解除注释
            //INALocator3 locator = naContext.Locator as INALocator3;
            //locator.ExcludeRestrictedElements = true;
            //locator.CacheRestrictedElements(naContext);

            int rowsInCursor = 0;
            int rowsLocated = 0;
            naLoader.Load(inputStopsFClass.Search(new QueryFilterClass(), false) as ICursor, new CancelTrackerClass(), ref rowsInCursor, ref rowsLocated);

            //Message all of the network analysis agents that the analysis context has changed
            ((INAContextEdit)naContext).ContextChanged();

            //Solve
            INASolver naSolver = naContext.Solver;
            IGPMessages gpMessage = new GPMessagesClass();
            naSolver.Solve(naContext, gpMessage, new CancelTrackerClass());

            //Save the layer to disk
            EsriUtility.SaveLayerToDisk(naLayer as ILayer, @"E:\data\output\Route5.lyr");

            //IFeatureClass routeFC = naContext.NAClasses.get_ItemByName("Routes") as IFeatureClass;
            nodes = EsriUtility.GetNodes(routesFC);
        }

        /// <summary>
        /// Create a new network analysis layer and set some solver settings
        /// </summary>
        private INALayer CreateRouteAnalysisLayer(String layerName, INetworkDataset networkDataset)
        {
            INARouteSolver naRouteSolver = new NARouteSolverClass();
            INASolverSettings naSolverSettings = naRouteSolver as INASolverSettings;
            //INASolverSettings可以设置权重字段，设置转弯，设置方向等
            INASolver naSolver = naRouteSolver as INASolver;

            //Get the NetworkDataset's Data Element
            //IDENetworkDataset相当于网络数据集的属性信息，右键网络数据集得到的属性信息，但是只是对属性信息的一个简单描述
            IDatasetComponent datasetComponent = networkDataset as IDatasetComponent;
            IDENetworkDataset deNetworkDataset = datasetComponent.DataElement as IDENetworkDataset;

            //Create the NAContext and bind to it
            //INAContext实际上就是路径分析图层，在TOC中的目录的内容
            INAContext naContext;
            naContext = naSolver.CreateContext(deNetworkDataset, layerName);
            INAContextEdit naContextEdit = naContext as INAContextEdit;
            naContextEdit.Bind(networkDataset, new GPMessagesClass());

            //Create the NALayer
            INALayer naLayer;
            naLayer = naSolver.CreateLayer(naContext);
            (naLayer as ILayer).Name = layerName;

            //Set properties on the route solver interface
            naRouteSolver.FindBestSequence = true;
            naRouteSolver.PreserveFirstStop = true;
            naRouteSolver.PreserveLastStop = false;
            naRouteSolver.UseTimeWindows = false;
            naRouteSolver.OutputLines = esriNAOutputLineType.esriNAOutputLineTrueShapeWithMeasure;

            //Set some properties on the general INASolverSettings interface
            //如果到了有限制和方向的，这里需要解除注释
            ////IStringArray restrictions = naSolverSettings.RestrictionAttributeNames;
            ////restrictions.Add("Oneway");
            ////naSolverSettings.RestrictionAttributeNames = restrictions;
            
            naSolver.UpdateContext(naContext, deNetworkDataset, new GPMessagesClass());

            //Return the layer
            return naLayer;
        }

       
    }
}
